#include "SocketHandler.h"
#include "Logger.h"
#include "IniFile.h"
#include "Singleton.h"
#include "Task.h"
#include "AutoLock.h"
#include "TaskDispatcher.h"
#include "ServerSocket.h"
#include "TaskFactory.h"

using namespace ddserver::thread;
using namespace ddserver::utility;
using namespace ddserver::socket;
using namespace ddserver::task;

SocketHandler::SocketHandler()
{

}

SocketHandler::~SocketHandler()
{
    if(m_epoll != NULL)
    {
        delete m_epoll;
        m_epoll = NULL;
    }

    if(m_server != NULL)
    {   
        delete m_server;
        m_server = NULL;
    }
}

void SocketHandler::listen(const string & ip, int port)
{
    m_server = new ServerSocket(ip,port);
}

void SocketHandler::attach(Socket* socket)
{
    AutoLock lock(&m_mutex);
    m_epoll->add(socket->m_sockfd,(void*)socket,(EPOLLONESHOT|EPOLLIN|EPOLLHUP|EPOLLERR));
}

void SocketHandler::detach(Socket* socket)
{
    AutoLock lock(&m_mutex);
    m_epoll->del(socket->m_sockfd,(void*)socket,(EPOLLONESHOT | EPOLLIN |EPOLLHUP|EPOLLERR));
}

void SocketHandler::modify(Socket* socket)
{
    AutoLock lock(&m_mutex);
    m_epoll->mod(socket->m_sockfd, (void*)socket,EPOLLOUT);
}

void SocketHandler::remove(Socket* socket)
{
    socket->close();
    m_sockpool.release(socket);
}

void SocketHandler::handle(int max_connections, int wait_time,int servertype)
{
    m_epoll = new EventPoller(false);
    m_epoll->create(max_connections);
    m_epoll->add(m_server->m_sockfd, m_server, (EPOLLIN | EPOLLHUP | EPOLLERR));
    m_sockpool.init(max_connections);

    log_debug("epoll wait time: %dms,servertype=%d", wait_time,servertype);
    while (true)
    {
        int num = m_epoll->wait(wait_time);
        if (num == 0)
        {
            //log_debug("no events");
            continue;
        }

        log_debug("num = %d",num);
        for (int i = 0; i < num; i++)
        {
            if (m_server == static_cast<Socket *>(m_epoll->m_events[i].data.ptr)) //连接socket
            {
                int soctfd = m_server->accept();
                Socket * socket = m_sockpool.allocate();
                if (socket == NULL)
                {
                    log_error("socket pool is empty");
                    break;
                }
                socket->m_sockfd = soctfd;
                socket->set_non_blocking();
                attach(socket);
                log_debug("socket accept event:attach=0x%08x",socket);
            }
            else
            {
                Socket * socket = static_cast<Socket *>(m_epoll->m_events[i].data.ptr);
                if (m_epoll->m_events[i].events & EPOLLHUP)
                {
                    log_error("socket %d closed by peer.", socket->m_sockfd);
                    detach(socket);
                    remove(socket);
                }
                else if (m_epoll->m_events[i].events & EPOLLERR)
			    {
                    log_error("socket %d log_error.", socket->m_sockfd);
                    detach(socket);
                    remove(socket);
			    }
                else if (m_epoll->m_events[i].events & EPOLLIN)
                {
                    detach(socket);
                    log_debug("socket read event,detach=0x%08x",socket);
                    Task* task = TaskFactory::create(socket,servertype);
                    Singleton<TaskDispatcher>::instance()->assign(task);
                }
            }
        }
    }
}
